# GPL3 or any later version

import os
import json
import time

import gi
import threading
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
from gi.repository import Gdk
from gi.repository import GLib

from modules import wallet
from modules import images
from modules import ui
from modules import transactions as tmodule
from modules import graphs

def select_dialogue(win, mode="normal"):

    # This is an item selector.

    dialogWindow = Gtk.Dialog("Select Item",
            buttons=(),
        )
    dialogWindow.set_size_request(400, 400)

    r = Gtk.VBox()
    r.ret = None
    
    def todo(w, win, item):
        r.ret = item
        try:
            if type(item) == dict:
                item["amount"] = item["amount"].get_value()
                item["price"] = item["price"].get_value()
        except:
            pass
        dialogWindow.destroy()
    
    box = dialogWindow.get_content_area()
    select_widget(win, box, todo, mode=mode)


    
    box.show_all()
    response = dialogWindow.run()
    dialogWindow.destroy()

    return r.ret
    
def select_widget(win, box, todo, mode="normal"):

    # Draws widget for searching and selecting items.

    search_box = Gtk.HBox()
    box.pack_start(search_box, 0,0,1)

    amount_entry, price_entry = False, False
    
    if mode == "transaction_add":

        totals = wallet.get_totals(win.wallet)
        currancy = totals.get("currancy", "$")

        # amount of the item
        search_box.pack_start(Gtk.Label(" x "),0,0,0)
        amount_adjust = Gtk.Adjustment(1,
                                       lower=-10000000000000000000,
                                       upper=10000000000000000000,
                                       step_increment=1) 
        amount_entry  = Gtk.SpinButton(adjustment=amount_adjust,
                                       digits=2)
        search_box.pack_start(amount_entry,0,0,0)

        search_box.pack_start(Gtk.Label(" "+currancy+" "),0,0,0)
        price_adjust = Gtk.Adjustment(0,
                                       lower=-10000000000000000000,
                                       upper=10000000000000000000,
                                       step_increment=1) 
        price_entry  = Gtk.SpinButton(adjustment=price_adjust,
                                      digits=2)
        search_box.pack_start(price_entry,0,0,0)

        sepbox = Gtk.HBox()
        sepbox.set_size_request(20,20)
        search_box.pack_start(sepbox,0,0,0)

    def on_changed(w):
        win.search_item = search.get_text()

    def on_search(w):
        refresh_items(win, pack, todo, amount_entry, price_entry, mode=mode, search=search.get_text())
        
    search = Gtk.Entry()
    search.connect("changed", on_changed)
    search.connect("activate", on_search)
    search_box.pack_start(search, 1,1,0)
    
    scrl = Gtk.ScrolledWindow()
    scrl.set_vexpand(0)
    box.pack_start(scrl, 1,1,1)

    pack = Gtk.VBox()
    scrl.add(pack)

    refresh_items(win, pack, todo, amount_entry, price_entry, mode=mode)
    return (win, pack, todo, amount_entry, price_entry, "", mode)

def refresh_items(win, pack, todo, amount_entry, price_entry, search="", mode="normal"):

    
    for i in pack.get_children():
        i.destroy()
    
    flowbox = Gtk.FlowBox()
    flowbox.set_valign(Gtk.Align.START)
    flowbox.set_max_children_per_line(30)
    flowbox.set_selection_mode(Gtk.SelectionMode.NONE)

    
    def on_add_item(w):
        editor(win, new=True)
        refresh_items(win, pack, todo, amount_entry, price_entry, search=search, mode=mode)
    
    add_item = Gtk.Button()
    add_item.add(ui.icon(win, "list-add"))
    add_item.set_relief(Gtk.ReliefStyle.NONE)
    flowbox.add(add_item)
    add_item.connect("clicked", on_add_item)

    folder = wallet.save_folder()+"items/"

    try:
        items = list(os.walk(folder))[0][2]
        items = sorted(items)
    except:
        items = []
    
    for i in items:

        with open(folder+i) as json_file: 
            idata = json.load(json_file) 

        if search:
            if search.lower() not in idata.get("name").lower() and search.lower() not in i.lower():
                continue
            
        item_button = Gtk.Button()
        if mode == "transaction_add":
            item_button.connect("clicked", todo, win, {"item":i.replace(".json", ""),
                                                       "amount":amount_entry,
                                                       "price":price_entry})
        else:
            item_button.connect("clicked", todo, win, i)
        item_button.set_relief(Gtk.ReliefStyle.NONE)
        item_box = Gtk.VBox()
        item_button.add(item_box)
        save_as = idata.get("image", "")
        if os.path.exists(save_as):
            image = ui.load(win, ui.net_image_calculation, ui.net_image_render, "", 100 , save_as, False)
        else:
            image = ui.icon(win, "package-x-generic")

        item_box.pack_start(image, 0,0,0)
        item_box.pack_start(Gtk.Label(str(idata.get("name", ""))), 0,0,0)
        item_box.pack_start(Gtk.Label(i.replace(".json", "")),0,0,0)
        flowbox.add(item_button)

    
    flowbox.show_all()
    pack.pack_start(flowbox, 1,1,1)

def editor(win, item="", new=False):

    # editor

    currancy = wallet.get_totals(win.wallet).get("currancy", "$")
    
    folder = wallet.save_folder()+"items/"
    try:
        os.makedirs(folder)
    except:
        pass

    data = {}
    edit_id = True

    try:
        search = win.search_item
    except:
        search = ""

    if not item:
        item = search
    
    if item:
        try:
            if not item.endswith(".json"):
                item = item+".json"
            with open(folder+item) as json_file: 
                data = json.load(json_file)
            item = item.replace(".json", "")
            edit_id = False
        except:
            pass
        
    
    if not data:

        
        data = {
            "name":"",
            "image":""}

        
        try:
            item = str(int(search))
        except:
            data["name"] = search
        
    
    dialogWindow = Gtk.Dialog("Item",
            buttons=(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
                     Gtk.STOCK_OK, Gtk.ResponseType.OK),
        )
    dialogWindow.set_size_request(200, 200)
    
    box = dialogWindow.get_content_area()

    main_data_box = Gtk.HBox()
    box.pack_start(main_data_box, 0,1,1)

    # IMAGE

    def image_edit(w):

        search = id_entry.get_text()+" "+name_entry.get_text()

        if search:
            images.select_image(win, search)
            save_as = win.return_search
            data["image"] = save_as
            add_image.get_children()[0].destroy()
            
            image = ui.load(win, ui.net_image_calculation, ui.net_image_render, "", 100 , save_as, False)
            add_image.add(image)
            add_image.show_all()
        
    add_image = Gtk.Button()
    main_data_box.pack_start(add_image, 0,0,0)
    add_image.connect("clicked", image_edit)
    add_image.set_relief(Gtk.ReliefStyle.NONE)
    
    if not data.get("image"):
        add_image.add(ui.icon(win, "image-x-generic"))
        
    else:
        save_as = data.get("image")
        image = ui.load(win, ui.net_image_calculation, ui.net_image_render, "", 100 , save_as, False)
        add_image.add(image)
        
    text_data_box = Gtk.VBox()
    main_data_box.pack_start(text_data_box, 1,1,1)

    # ID

    def on_entry(w, d):
        data[d] = w.get_text()


        
    id_box = Gtk.HBox()
    text_data_box.pack_start(id_box, 0,0,5)
    id_box.pack_start(Gtk.Label(" ID: "), 0,0,0)
    id_entry = Gtk.Entry()
    id_entry.grab_focus()
    id_entry.set_sensitive(edit_id)
    
    id_box.pack_end(id_entry, 0,0,0)

    # NAME

    name_box = Gtk.HBox()
    text_data_box.pack_start(name_box, 0,0,5)
    name_box.pack_start(Gtk.Label(" Name: "), 0,0,0)
    name_entry = Gtk.Entry()
    name_entry.connect("changed", on_entry, "name")
    name_box.pack_end(name_entry, 0,0,0)

    # TOTALS

    total_amount = 0
    total_money = 0
    all_prices = []
    all_trans = []
    graph_data = {"items":[],
                  "zoom":[0,0],
                  "allow_negative":True
        }
    
    tfolder = wallet.save_folder()+"wallets/"+win.wallet+"/transactions/"
    try:
        transactions = list(os.walk(tfolder))[0][2]
        transactions = sorted(transactions)
    except:
        transactions = []


        
    for i in transactions:
        try:
            with open(tfolder+i) as json_file: 
                tdata = json.load(json_file)
            for b in tdata.get("items", []):
                
                if b.get("item") == item:
                    all_trans.append(i)
                    total_money = total_money + ( b.get("price", 0) * b.get("amount", 0))
                    graph_data["items"].append({"amount":b.get("price", 0) * b.get("amount", 0),
                                                "timestamp":int(i.replace(".json", ""))
                                                                })
                    all_prices.append(b.get("price", 0))
                    total_amount = total_amount + b.get("amount", 0)
        except Exception as e:
            print(i, e )
        
    try:
        average_price = sum(all_prices) / len(all_prices)
    except:
        average_price = 0

            
    # Notebook
    notebook = Gtk.Notebook()
    notebook.set_scrollable(True)
    if not new:
        box.pack_start(notebook, 1,1,1)

    totals_box = Gtk.VBox()
    totals_box.pack_start(Gtk.Label("Total Items: "+str(round(total_amount, 2))), 0,0,0)
    totals_box.pack_start(Gtk.Label("Total Money: "+currancy+str(round(total_money,2))), 0,0,0)
    totals_box.pack_start(Gtk.Label("Average Price: "+currancy+str(round(average_price,2))), 0,0,0)
    
    detailsbox = Gtk.HBox()
    detailsbox.pack_start(Gtk.Label("  Totals  "), True, True, True)
    detailsbox.show_all()
    notebook.append_page(totals_box, detailsbox)


    # TRANSACTIONS

    transactions_scrl = Gtk.ScrolledWindow()
    trbox = Gtk.VBox()
    transactions_scrl.add(trbox)

    for i in all_trans:

        with open(tfolder+i) as json_file: 
            tdata = json.load(json_file)

        def on_tbutton(w, name):
            tmodule.editor(win, name)
            
        tbutton = Gtk.Button()
        tbutton.connect("clicked", on_tbutton, i)
        tbutton.set_relief(Gtk.ReliefStyle.NONE)
        tbox = Gtk.HBox()
        tbutton.add(tbox)

        tbox.pack_start(ui.icon(win,"task-past-due"), 0,0,0)

        try:
            tdate = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(int(i.replace(".json", ""))))
        except Exception as e:
            print( e )
            tdate = "[Date Unknown]"

        tbox.pack_start(Gtk.Label(tdate), 1,1,1)
        tbox.pack_end(Gtk.Label(str(round(tdata.get("total", 0), 2))), 0,0,5)
        trbox.pack_start(tbutton, 0,0,0)
    
    detailsbox = Gtk.HBox()
    detailsbox.pack_start(Gtk.Label("  Transactions  "), True, True, True)
    detailsbox.show_all()
    notebook.append_page(transactions_scrl, detailsbox)
    
    # GRAPH

    the_graph = graphs.graph(win, graph_data, "Graph", currancy=currancy, add_value=0)
    detailsbox = Gtk.HBox()
    detailsbox.pack_start(Gtk.Label("  Graph  "), True, True, True)
    detailsbox.show_all()
    notebook.append_page(the_graph, detailsbox)


    
    # Auto filling

    if item:
        id_entry.set_text( str(item).replace(".json", "") )
        name_entry.grab_focus()

    name_entry.set_text(str(data.get("name", "")))

    box.show_all()
    
    response = dialogWindow.run()
    if response == Gtk.ResponseType.OK:

        item = id_entry.get_text()

        if new: # Failsafe for in case the user will accidentaly overwrite
            n = 0 # an existing item by mistake. 
            nn = item
            while os.path.exists(folder+str(item)+".json"):
                n = n + 1
                item = nn+"_"+str(n)
        
        filename = folder+str(item)+".json"
        with open(filename, "w") as fp:
            json.dump(data, fp, indent=4)

    dialogWindow.destroy()
